using System;
using System.Linq;
using CommonBehaviors.Actions;
using Styx;
using Styx.Logic.Combat;
using Styx.Logic.Inventory;
using Styx.Logic.Pathing;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using TreeSharp;
using Action = TreeSharp.Action;

namespace Altarboy
{
    class AltarboyComposites
    {
    

        #region Delegates
            public delegate bool SimpleBoolReturnDelegate(object context);
            public delegate WoWUnit UnitSelectionDelegate(object context);
        #endregion

            // Current Player   
            public static LocalPlayer Me { get { return StyxWoW.Me; } }



            public static Composite CastMindSear(SimpleBoolReturnDelegate extra)
            {

                //Todo - Should add logic to check for CC'ed targets within Mindsear Range.
                return new Decorator(
                 ret => extra(ret),  
                 new Sequence(
                            //new Action(ret => Navigator.PlayerMover.MoveStop()), | Beyond annoying.                           
                            new Action(ret => Me.CurrentTarget.Face()),
                            new Action(ret => CastManager.CastSpell("Mind Sear", Me.CurrentTarget))
                  )              
                );
            }


            public static Composite UseSlottedItem(SimpleBoolReturnDelegate extra, WoWItem slottedItem )
            {              
                   return new Decorator(
                    ret => extra(ret) && (
                        slottedItem != null &&
                        slottedItem.BaseAddress != 0 &&                     
                        slottedItem.Cooldown == 0                                                                                                     
                    ),                   
                    new Action(delegate{                    
                     slottedItem.Use();
                     Logger.CastLog(slottedItem.Name, Me.Name);
                    } )                    
                 );

            }
                               

          public static Composite CastSpell(string spellName, SimpleBoolReturnDelegate extra,  WoWUnit target)
            {
                //using current target no matter what... just testing something
                return new Decorator(
                    ret => extra(ret) && CastManager.CanCast(spellName, Me.CurrentTarget) ,
                    new Action(delegate{                                         
                        CastManager.CastSpell(spellName, Me.CurrentTarget);                      
                    })
                      
                );
           }

        public static Composite BuffSelf(string buffName, SimpleBoolReturnDelegate extra)
        {
            return new Decorator(
                ret => extra(ret) && !Me.Auras.ContainsKey(buffName) && CastManager.CanCast(buffName, Me),
                new Action(delegate { CastManager.CastSpell(buffName, Me); })
             );
        }

        public static Composite BuffParty(string buffName, SimpleBoolReturnDelegate extra)
        {
            bool any = PartyManager.GroupMembers.Any(u => !u.Dead && !u.IsGhost && (u.IsInMyPartyOrRaid || u.IsMe) && !u.Auras.ContainsKey(buffName) && u.Distance < 40);
            return new Decorator( ret => extra(ret) &&
                    (Me.IsInParty || Me.IsInRaid ) &&
                    any, BuffSelf(buffName, ret => true)
             );
        }
        public static bool CanPowerWordShield()
        {
            return !AuraManager.HasMyAura("Weakened Soul", Me) && !SpellManager.Spells["Power Word: Shield"].Cooldown;
        }


        public static Composite CommonPriestBuffs()
        {
            return new PrioritySelector(
                HandleFalling(),
                BuffSelf("Power Word: Fortitude", ret => (AltarboySettings.Instance.BuffFortitude && AltarboySettings.Instance.BuffFortitudeWhileInCombat)),
                BuffParty("Power Word: Fortitude", ret => (AltarboySettings.Instance.BuffFortitude && AltarboySettings.Instance.BuffFortitudeOnParty && AltarboySettings.Instance.BuffFortitudeWhileInCombat)),
                BuffSelf("Shadow Protection", ret => (AltarboySettings.Instance.BuffShadowProtection && AltarboySettings.Instance.BuffShadowProtectionWhileInCombat)),
                BuffParty("Shadow Protection", ret => (AltarboySettings.Instance.BuffShadowProtection && AltarboySettings.Instance.BuffShadowProtectionOnParty && AltarboySettings.Instance.BuffShadowProtectionWhileInCombat)),
                BuffSelf("Shadowform", ret => (AltarboySettings.Instance.UseShadowForm)),
                BuffSelf("Vampiric Embrace", ret => (AltarboySettings.Instance.UseVampiricEmbrace))
              
            );
        }

        public static Composite HandleFalling()
        {
            return new Decorator(ret => AltarboySettings.Instance.LevitateWhileFalling && Me.IsFalling,
             
                new PrioritySelector(
                    
                    //Do I already have levitate
                    new Decorator(ret => AuraManager.HasMyAura("Levitate", Me),
                        new Sequence(
                            new WaitContinue(TimeSpan.FromSeconds(2), ret => AuraManager.HasMyAura("Levitate", Me), new ActionAlwaysSucceed()),
                            new Action(delegate{Lua.DoString("CancelUnitBuff(\"player\", \"Levitate\")");})
                        )
                    ),

                    //I don't have levitate.
                    new Decorator(ret => !AuraManager.HasMyAura("Levitate", Me),
                        new Sequence(
                            new WaitContinue(TimeSpan.FromSeconds(4), ret => Me.IsFalling,new ActionAlwaysSucceed()),
                            new Decorator(ret => Me.IsFalling, BuffSelf("Levitate", ret => (Me.IsFalling)))
                        )
                   )
                )
           );
        }

        public static Composite UseItemById(int itemId, SimpleBoolReturnDelegate extra)
            {
                return new PrioritySelector(
                    new Decorator(
                         ret => extra(ret),
                         new Action(ret => CastManager.UseItemById(itemId))                        
                    ));
            }


        //Credits Singular
        public static Composite DrinkForMana()
        {
            return new PrioritySelector( // Check if we're allowed to eat (and make sure we have some food. Don't bother going further if we have none.
                new Decorator(
                    ret => !StyxWoW.Me.IsSwimming && StyxWoW.Me.HealthPercent <= AltarboySettings.Instance.MinRestHealthPercent  && !StyxWoW.Me.HasAura("Food") && Consumable.GetBestFood(false) != null,
                    new PrioritySelector(
                        new Decorator(
                            ret => StyxWoW.Me.IsMoving,
                            new Action(ret => Navigator.PlayerMover.MoveStop())),
                        new Action(
                            ret =>
                            {
                                Styx.Logic.Common.Rest.FeedImmediate();
                                StyxWoW.SleepForLagDuration();
                            })
                        )),
                // Make sure we're a class with mana, if not, just ignore drinking all together! Other than that... same for food.
                new Decorator(
                    ret => !StyxWoW.Me.IsSwimming && StyxWoW.Me.PowerType == WoWPowerType.Mana && StyxWoW.Me.ManaPercent <= AltarboySettings.Instance.MinRestManaPercent && !StyxWoW.Me.HasAura("Drink") && Consumable.GetBestDrink(false) != null,
                    new PrioritySelector(
                        new Decorator(
                            ret => StyxWoW.Me.IsMoving,
                            new Action(ret => Navigator.PlayerMover.MoveStop())),
                        new Action(
                            ret =>
                            {
                                Styx.Logic.Common.Rest.DrinkImmediate();
                                StyxWoW.SleepForLagDuration();
                            })
                        )),
                // This is to ensure we STAY SEATED while eating/drinking. No reason for us to get up before we have to.
                new Decorator(
                    ret =>
                    (StyxWoW.Me.HasAura("Food") && StyxWoW.Me.HealthPercent < 95) || (StyxWoW.Me.HasAura("Drink") && StyxWoW.Me.PowerType == WoWPowerType.Mana && StyxWoW.Me.ManaPercent < 95),
                    new ActionAlwaysSucceed()),
                new Decorator(
                    ret => (StyxWoW.Me.PowerType == WoWPowerType.Mana && StyxWoW.Me.ManaPercent <= AltarboySettings.Instance.MinRestManaPercent) || StyxWoW.Me.HealthPercent <= AltarboySettings.Instance.MinRestHealthPercent,
                    new Action(ret => Logger.Log("We have no food/drink. Waiting to recover our health/mana back")))
                );

        }
            
    }
}
